package mapReader;



import mapReader.commandos.Commando;
import mapReader.commandos.Join;
import mapReader.commandos.Name;
import util.StringUtils;

import communication.Protocol;

import exceptions.NotImplementedException;

public class GhostProtocol extends Protocol {
	
	private GhostInformatie ghostInformatie;
	private CommandoManager commandoManager;
	private GhostProtocolToestand toestand;

	private int joinTeller;
	private int aantalJoins;
	
	public GhostProtocol(GhostInformatie ghostInformatie){
		this(ghostInformatie, 4);
	}
	
	public GhostProtocol(GhostInformatie ghostInformatie, int aantalJoins){	
		setGhostInformatie(ghostInformatie);
		setCommandoManager(new CommandoManager(this));
		setToestand(GhostProtocolToestand.INIT);

		setJoinTeller(0);
		setAantalJoins(aantalJoins);
	}
	
	public GhostInformatie getGhostInformatie(){
		return ghostInformatie;
	}
	
	private void setGhostInformatie(GhostInformatie gi){
		this.ghostInformatie = gi;
	}
	
	public CommandoManager getCommandoManager(){
		return commandoManager;
	}
	
	private void setCommandoManager(CommandoManager c){
		this.commandoManager = c;
	}
	
	public GhostProtocolToestand getToestand(){
		return toestand;
	}
	
	public void setToestand(GhostProtocolToestand nieuweToestand){
		toestand = nieuweToestand;

	}
	
	public int getJoinTeller(){
		return joinTeller;
	}
	
	private void setJoinTeller(int i){
		this.joinTeller = i;
	}
	
	public int getAantalJoins(){
		return aantalJoins;
	}
	
	private void setAantalJoins(int i){
		this.aantalJoins = i;
	}

	
	public SpelerManager getSpelerManager(){
		return this.ghostInformatie.getSpelerManager();
	}
	
	//Inkomend verwerken
	public void verwerkInkomend(byte[] bytes){
	
		verwerkInkomend(new String(bytes));
		
	}
	
	public void verwerkInkomend(String bericht) {
		
		if(!bericht.endsWith("\n"))
			throw new CommunicatieException();
		
		StringUtils su = new StringUtils();
		String[] stukken = su.split(bericht.substring(0, bericht.length() - 1), ' ');
		
		//Filteren
		if(getSpelerManager().getHuidigeSpeler().getNaam().equals(stukken[0]))
			return;
		
		//Speler en commando parsen
		Commando commando = getCommand(stukken);
		Speler speler = getSpeler(commando, stukken);
		
		String[] parameters = getParameters(commando, stukken, stukken[0]);
		
		commando.verwerk(speler, parameters);
	}
	
	private Commando getCommand(String[] stukken)
	{
		if(getCommandoManager().heeftAnoniemCommandoMetNaam(stukken[0]))
		{
			return getCommandoManager().getCommandoMetNaam(stukken[0]);
		}
		else
		{
			return getCommandoManager().getCommandoMetNaam(stukken[1]);
		}
	}
	
	private Speler getSpeler(Commando commando, String[] stukken)
	{
		if(commando.isAnoniem())
			return null;
		
		if(commando.accepteerOnbekendeSpeler())
			return null;
		
		return getSpelerManager().getSpelerMetNaam(stukken[0]);
	}	
	
	private String[] getParameters(Commando commando, String[] stukken, String spelerNaam)
	{
		int begin = 0;
		int index = 0;
		int aantalExtra = 0;
		
		if(commando.isAnoniem())
			begin = 1;
		else
			begin = 2;
		
		if(commando.accepteerOnbekendeSpeler())
			aantalExtra = 1;
		
		String[] parameters = new String[stukken.length - begin + aantalExtra];
		
		if(commando.accepteerOnbekendeSpeler())
			parameters[index++] = spelerNaam;
		
		for(int i = begin; index < parameters.length; index++, i++)
		{
			parameters[index] = stukken[i];
		}
		
		return parameters;
	}

	
	public void spelerJoined() {
		joinTeller += 1;
		
		if(getJoinTeller() == getAantalJoins())
			exitJoin();
	}
	
	/**
	 * Deze methode niet rechtstreeks gebruiken, maar gebruik de stuur
	 * methode in het commando.
	 * 
	 * @param command
	 * @param parameters
	 */
	public void stuur(Commando command, String[] parameters) {
		StringBuilder string = new StringBuilder();
		
		if(!command.isAnoniem()) {
			string.append(getSpelerManager().getHuidigeSpeler().getNaam());
			string.append(' ');
		}
		
		string.append(command.getNaam());
		
		for(String param : parameters){
			string.append(' ');
			string.append(param);
		}
		
		string.append('\n');
		
		getKanaal().stuurBericht(string.toString().getBytes());
	}
	
	public void begin() {
		setToestand(GhostProtocolToestand.JOIN);
		stuur(new Join(this), new String[] {} );
	}
	
	public void updateBericht(){
		throw new NotImplementedException(); // TODO Auto-generated method stub
		
	}
	
	public void exitJoin() {
		setToestand(GhostProtocolToestand.NAAM);
		(new Name(this)).stuur();
		setToestand(GhostProtocolToestand.LUS);
	}
}
